package com.adinnet.common.outbound.pay.wxpay;

import com.adinnet.common.outbound.pay.utils.HttpClientUtils;
import com.adinnet.common.outbound.pay.utils.SignConstants;
import com.adinnet.common.outbound.pay.utils.ToolUtils;
import com.adinnet.common.outbound.pay.utils.WXSignature;
import com.adinnet.common.utils.PropertiesConfig;
import com.adinnet.common.utils.XMLUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author: sunjianbo
 * @date: 2019/4/26 11:25
 */
@Component
public class WeixinPayApi {
    private static Logger log = LoggerFactory.getLogger(WeixinPayApi.class);

    //API https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=5

    /**
     * 微信预付订单     本接口涉及到1~3
     * API https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_4&index=3
     * API https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=5
     * 1.小程序请求服务器进行预下单，上送商品详情、金额、openid
     * 2.服务器端接收请求，根据请求订单数据、生成第三方订单号，调用微信的 统一下单接口
     * 3.服务器收到预下单信息后，签名并组装支付数据，返回给小程序。所需数据见：小程序支付接口
     * 4.小程序前端发起支付，并支付完成
     * 5.服务器收到回调。
     *
     * @param openId
     * @param orderNo     商户系统内部订单号，要求32个字符内，只能是数字、大小写字母_-|*且在同一个商户号下唯一。详见商户订单号
     * @param body        商品名称    例子:腾讯充值中心-QQ会员充值
     * @param totalAmount 整数字符串 单位分. 不能有小数点
     * @param notifyUrl   付款成功后
     * @param request
     * @return
     */
    public Map<String, String> weixinPrePay(String openId, String orderNo, String body, String totalAmount,
                                            String notifyUrl, HttpServletRequest request, Integer type) {
        // totalAmount="1";
        //1.小程序请求服务器进行预下单，上送商品详情、金额、openid
        //1.1组装预下单的请求数据
        totalAmount = String.valueOf((new Double(totalAmount)).longValue());
        Map<String, String> orderParam = new HashMap<>();
        orderParam.put("openid", openId);
        orderParam.put("appid", PropertiesConfig.weiXinSmallProgramId);
        orderParam.put("mch_id", PropertiesConfig.weiXinMchId);
        orderParam.put("nonce_str", ToolUtils.getUuid());
        orderParam.put("body", body);
        orderParam.put("notify_url", notifyUrl);
        orderParam.put("out_trade_no", orderNo);
        orderParam.put("total_fee", totalAmount);//单位分
        orderParam.put("spbill_create_ip", getIpAddr(request));
        orderParam.put("sign_type", "MD5");
        orderParam.put("trade_type", "JSAPI");
        orderParam.put("device_info", String.valueOf(type));


        String sign = WXSignature.createSign(SignConstants.CHARSET_UTF8, orderParam, PropertiesConfig.weiXinPartnerKey);
        orderParam.put("sign", sign);
        orderParam.remove("key");
        //1.2发送post数据到微信预下单
        String requestXml = WXSignature.getRequestXml(orderParam);
        log.info("\n本机验证签名==>\t" + WXSignature.verifySign(requestXml, PropertiesConfig.weiXinPartnerKey));
        log.info("request==>\t" + requestXml);
        String result = HttpClientUtils.httpsRequest(PropertiesConfig.weiXinUnifiedOrderUrl, "POST", requestXml);
        log.info("result==>\t" + result);
        //2服务器端接收请求，根据请求订单数据、生成第三方订单号，调用微信的统一下单接口
        Map map = null;
        try {
            map = XMLUtils.doXMLParse(result);
            log.info("resultMap==>\t" + map + "\n");
        } catch (Exception e) {
            e.printStackTrace();
        }
        String appId = (String) map.get("appid");
        String mchId = (String) map.get("mch_id");
        String return_code = (String) map.get("return_code");
        String result_code = (String) map.get("result_code");
        String returnMsg = (String) map.get("return_msg");

        Map<String, String> resultMap = new HashMap<>();
        // 解析返回订单数据
        //异常
        if (!PropertiesConfig.weiXinSmallProgramId.equals(appId) || !PropertiesConfig.weiXinMchId.equals(mchId)) {
            log.error("appId>>>>>>>>>>>>\t" + appId + "\nmchId>>>>>>>>>>>>\t" + mchId);
            resultMap.put("status", SignConstants.FAIl);
            resultMap.put("errorMsg", returnMsg);
        }
        //正常
        //3.服务器收到预下单信息后，签名并组装支付数据，返回给小程序。所需数据见：小程序支付接口
        if (return_code.contains(SignConstants.SUCCESS) && result_code.contains(SignConstants.SUCCESS)) {
            String prepay_id = (String) map.get("prepay_id");
            String seconds = String.valueOf(System.currentTimeMillis() / 1000L).substring(0, 10);
            Map<String, String> signParam = new HashMap<>();

            String uuid = ToolUtils.getUuid();
            signParam.put("appId", appId);
            signParam.put("nonceStr", uuid);
            signParam.put("timeStamp", seconds);
            signParam.put("package", "prepay_id=" + prepay_id);
            signParam.put("signType", "MD5");

            String signAgain = WXSignature.createSign(SignConstants.CHARSET_UTF8, signParam,
                    PropertiesConfig.weiXinPartnerKey);
            resultMap.putAll(signParam);
            resultMap.put("paySign", signAgain);
            resultMap.put("orderNo",orderNo);
        }
        return resultMap;
    }

    //微信退款
    public Map<String, String> weixinRefund(String orderId, String orderNo, String serialNumber, String totalAmount,
                                            HttpServletRequest request) {
        // totalAmount="1";//TODO:正式上线前  干掉本行代码
        totalAmount = String.valueOf((new Double(totalAmount)).longValue());
        Map<String, String> orderParam = new HashMap<>();
        orderParam.put("appid", PropertiesConfig.weiXinSmallProgramId);
        orderParam.put("mch_id", PropertiesConfig.weiXinMchId);
        orderParam.put("nonce_str", ToolUtils.getUuid());
        orderParam.put("sign_type", "MD5");
        orderParam.put("out_refund_no", orderId);//退款单号:为了方便,使用订单ID
        orderParam.put("out_trade_no", orderNo);//商户订单号
        // orderParam.put("transaction_id", serialNumber);//微信订单号.注:商户订单号 与 微信订单号 二选一
        orderParam.put("total_fee", totalAmount);//订单总金额
        orderParam.put("refund_fee", totalAmount);//退款金额
        orderParam.put("notify_url", PropertiesConfig.wXRefundAsync);//TODO:新增 微信退款异步通知配置及接口

        String sign = WXSignature.createSign(SignConstants.CHARSET_UTF8, orderParam, PropertiesConfig.weiXinPartnerKey);
        orderParam.put("sign", sign);
        orderParam.remove("key");
        Map<String, String> resp = new HashMap<>();
        try {
            WXPay wxpay = new WXPay(new MyConfig());
            log.info("退款请求数据====》》" + orderParam);
            resp = wxpay.refund(orderParam);
            log.info("退款返回数据====》》" + resp);
            if (resp.get("result_code").equals("FAIL")) log.info("退款失败===》" + resp.get("err_code_des"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resp;
    }

    /**
     * 获取ip地址
     */
    public String getIpAddr(HttpServletRequest request) {
        String ip = null;
        try {
            ip = request.getHeader("x-forwarded-for");
            if (isBlankIp(ip))
                ip = request.getHeader("Proxy-Client-IP");
            if (isBlankIp(ip))
                ip = request.getHeader("WL-Proxy-Client-IP");
            if (isBlankIp(ip))
                ip = request.getHeader("HTTP_CLIENT_IP");
            if (isBlankIp(ip))
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            if (isBlankIp(ip))
                ip = request.getRemoteAddr();
            // 使用代理，则获取第一个IP地址
            if (!isBlankIp(ip) && ip.length() > 15)
                ip = ip.split(",")[0];
        } catch (Exception e) {
            e.printStackTrace();
        }
        if ("0:0:0:0:0:0:0:1".equals(ip)) {
            try {
                ip = InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
        }
        return ip;
    }

    private boolean isBlankIp(String str) {
        return str == null || str.trim().isEmpty() || "unknown".equalsIgnoreCase(str);
    }

}
